package cn.edu.cug.cs.gtl.oi.inventor.demo;

import cn.edu.cug.cs.gtl.api.wrapper.geometry3d.VolumeWrapper;
import cn.edu.cug.cs.gtl.api.wrapper.geometry3d.VoxelModelWrapper;
import cn.edu.cug.cs.gtl.oi.utils.Example;
import cn.edu.cug.cs.gtl.oi.utils.ViewerComponentsFactory;
import cn.edu.cug.cs.gtl.protos.VoxelModel;
import com.openinventor.inventor.SbBox3f;
import com.openinventor.inventor.SbDataType;
import com.openinventor.inventor.SbVec3i32;
import com.openinventor.inventor.nodes.SoDrawStyle;
import com.openinventor.inventor.nodes.SoGradientBackground;
import com.openinventor.inventor.nodes.SoSeparator;
import com.openinventor.inventor.viewercomponents.awt.IViewerExaminer;
import com.openinventor.ldm.nodes.SoTransferFunction;
import com.openinventor.volumeviz.nodes.SoVolumeData;
import com.openinventor.volumeviz.nodes.SoVolumeRender;

import java.awt.*;
import java.nio.*;

import java.awt.BorderLayout;
import java.awt.Component;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import com.openinventor.inventor.SbBox3f;
import com.openinventor.inventor.SbDataType;
import com.openinventor.inventor.SbDataType.DataTypes;
import com.openinventor.inventor.SbVec3i32;
import com.openinventor.inventor.nodes.SoSeparator;
import com.openinventor.inventor.viewercomponents.awt.IViewerExaminer;
import com.openinventor.ldm.nodes.SoTransferFunction;
import com.openinventor.volumeviz.nodes.SoVolumeData;
import com.openinventor.volumeviz.nodes.SoVolumeRender;



public class SimpleVolume extends Example
{

    private IViewerExaminer myViewer;

    public static void main(String[] args) {
        SimpleVolume example = new SimpleVolume();
        example.demoMain("SimpleVolume");
    }

    @Override
    public void start() {
        myViewer = ViewerComponentsFactory.createViewerExaminer();

        String fileName = "C:\\Open Inventor\\10.12.0 Java x64\\data\\volumeviz\\syn_64.VOL";
        VoxelModelWrapper vmw = new VoxelModelWrapper(new VolumeWrapper.VolFileReader(fileName));
        VoxelModel voxelModel = vmw.get();
        int c = voxelModel.getVoxelValueCount();
        int capacity = Long.valueOf(voxelModel.getXSize()*voxelModel.getYSize()*voxelModel.getZSize()).intValue()*Double.BYTES;
        ByteBuffer data = ByteBuffer.allocateDirect(capacity);
        data.order(ByteOrder.nativeOrder());
        DoubleBuffer doubleBuffer = data.asDoubleBuffer();
        for (int i = 0; i < c; i++) {
            //data.putDouble(i*Double.BYTES,voxelModel.getVoxelValue(i));
            doubleBuffer.put(i,voxelModel.getVoxelValue(i));
        }

        int dimX = Long.valueOf(voxelModel.getXSize()).intValue();
        int dimY = Long.valueOf(voxelModel.getYSize()).intValue();
        int dimZ = Long.valueOf(voxelModel.getZSize()).intValue();

        // Node to hold the volume data
        // In the first call we specify the voxel dimensions and the actual data.
        // In the second call we specify the 3D extent of the volume in modeling coords.
        SoVolumeData pVolData = new SoVolumeData();
        pVolData.data.setValue(new SbVec3i32(dimX, dimY, dimZ),
                new SbDataType(SbDataType.DataTypes.DOUBLE),data);
        SbBox3f sbBox3f = new SbBox3f(Double.valueOf(voxelModel.getOrigin().getX()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getY()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getZ()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getX()+voxelModel.getXSize()*voxelModel.getXStep()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getY()+voxelModel.getYSize()*voxelModel.getYStep()).floatValue(),
                Double.valueOf(voxelModel.getOrigin().getZ()+voxelModel.getZSize()*voxelModel.getZStep()).floatValue());
        pVolData.extent.setValue(sbBox3f);



        //Volume Size
//        int dimX = 10;
//        int dimY = 10;
//        int dimZ = 10;

        // Create data :
        // Note: 0 < data[i] < number of entries in the colorMap.
        // If each data value has the same value A the volume will be unicolor
        // with the color described by the Ath entries of the colorMap.
        // This volume data will use every color in the colorMap
//        int capacity = dimX * dimY * dimZ;
//        ByteBuffer data = ByteBuffer.allocateDirect(capacity);
//        data.order(ByteOrder.nativeOrder());
//        for (int i = 0; i < capacity; i++) {
//            data.put( Integer.valueOf(i % 256).byteValue() );
//        }

        // Node to hold the volume data
        // In the first call we specify the voxel dimensions and the actual data.
        // In the second call we specify the 3D extent of the volume in modeling coords.
//        SoVolumeData pVolData = new SoVolumeData();
//        pVolData.data.setValue(new SbVec3i32(dimX, dimY, dimZ),
//                new SbDataType(SbDataType.DataTypes.UNSIGNED_BYTE),data);
//        pVolData.extent.setValue(new SbBox3f( -dimX, -dimY, -dimZ, dimX, dimY, dimZ));

        // Use a predefined colorMap with the SoTransferFunction
        SoTransferFunction pTransFunc = new SoTransferFunction();
        pTransFunc.predefColorMap.setValue(SoTransferFunction.PredefColorMaps.AIRWAY);

        // Node in charge of drawing the volume
        SoVolumeRender pVolRender = new SoVolumeRender();

        SoSeparator r = new SoSeparator();
        r.addChild(new SoGradientBackground());
        SoDrawStyle soDrawStyle = new SoDrawStyle();
        r.addChild(soDrawStyle);
        r.setName("geometry");


        { // Assemble the scene graph
            // Note: SoVolumeRender must appear after the SoVolumeData node.
            SoSeparator root = new SoSeparator();
            root.addChild(pVolData);
            root.addChild(pTransFunc);
            root.addChild(pVolRender);
            r.addChild(root);
        }

        // Set up viewer:
        myViewer.setSceneGraph(r);
        myViewer.viewAll();

        final Component component = myViewer.getComponent();
        component.setPreferredSize(new java.awt.Dimension(600, 500));
        setLayout(new BorderLayout());
        add(component);
    }

    @Override
    public void stop()
    {
        myViewer.dispose();
    }
}
